package be.phl.obstacleapp;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import be.phl.model.DBAdapter;
import be.phl.model.DBAdapterDownloadBundle;
import be.phl.model.DBAdapterScreening;
import be.phl.model.DBAdapterUpload;
import be.phl.model.DBAdapterUser;
import be.phl.webservice.DownloadBundle;
import be.phl.webservice.PatientBundle;
import be.phl.webservice.PatientBundle.itemIdPair;
import be.phl.webservice.PictureContainer;
import be.phl.webservice.ScreeningBundle;
import be.phl.webservice.ScreeningBundle.ScreeningItemBundle;
import be.phl.webservice.ScreeningBundle.ScreeningRoomBundle;
import be.phl.webservice.ScreeningProblem;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class SyncActivity extends Activity {

	/**
	 * set up static variables
	 */
	private static final String SERVER_URL = MainData.getServerUrl();
	private static final String TAG = "SyncActivity";

	/**
	 * Keep track of the webservice task to ensure we can cancel it if
	 * requested.
	 */
	private WebserviceTask mWebserviceTask = null;
	private static boolean isSynchronising = false;

	// UI references
	private View mSyncButtonView;
	private View mSyncStatusView;
	private TextView mSyncMessage;
	private TextView mSyncStatusMessage;
	private ProgressBar mProgressBar;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_sync);
		// Show the Up button in the action bar.
		getActionBar().setDisplayHomeAsUpEnabled(true);

		mSyncButtonView = findViewById(R.id.sync_button_wrapper);
		mSyncStatusView = findViewById(R.id.sync_status);
		mSyncMessage = (TextView) findViewById(R.id.sync_message);
		mSyncStatusMessage = (TextView) findViewById(R.id.sync_status_message);
		mProgressBar = (ProgressBar) findViewById(R.id.login_progress_bar);
		mProgressBar.setProgress(0);

		findViewById(R.id.sync_button).setOnClickListener(
				new View.OnClickListener() {
					@Override
					public void onClick(View view) {

						if (MainData.isNetworkAvailable(SyncActivity.this)) {
							Log.i(TAG, "Start Synchronising");
							showProgress(true);
							mWebserviceTask = new WebserviceTask();
							mWebserviceTask.execute(new String[] {
									SERVER_URL,
									"/"
											+ MainData.getLoggedUser()
													.getUserName()
											+ "/"
											+ MainData.getLoggedUser()
													.getPassWord() });
							isSynchronising = true;
						} else {
							mSyncMessage.setText(R.string.error_connection);
							mSyncMessage.setTextColor(Color
									.parseColor("#FF0000"));
							mSyncMessage.setVisibility(View.VISIBLE);
						}

					}
				});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_sync, menu);
		return true;
	}
	
	@Override
    public void onBackPressed() {
        if (isSynchronising) {
        	Toast toast = Toast.makeText(this,
					"Wacht tot het synchroniseren is voltooid", Toast.LENGTH_LONG);
			toast.show();
        } else {
        	Intent mainAct = new Intent(this,
					MainActivity.class);

			this.startActivity(mainAct);
        }
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			// This ID represents the Home or Up button. In the case of this
			// activity, the Up button is shown. Use NavUtils to allow users
			// to navigate up one level in the application structure. For
			// more details, see the Navigation pattern on Android Design:
			//
			// http://developer.android.com/design/patterns/navigation.html#up-vs-back
			//
			if(isSynchronising) {
				Toast toast = Toast.makeText(this,
						"Wacht tot het synchroniseren is voltooid", Toast.LENGTH_LONG);
				toast.show();
			} else {
				NavUtils.navigateUpFromSameTask(this);
			}
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	/**
	 * Shows the progress UI and hides the login form.
	 */
	@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
	private void showProgress(final boolean show) {
		// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
		// for very easy animations. If available, use these APIs to fade-in
		// the progress spinner.
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
			int shortAnimTime = getResources().getInteger(
					android.R.integer.config_shortAnimTime);

			mSyncStatusView.setVisibility(View.VISIBLE);
			mSyncStatusView.animate().setDuration(shortAnimTime)
					.alpha(show ? 1 : 0)
					.setListener(new AnimatorListenerAdapter() {
						@Override
						public void onAnimationEnd(Animator animation) {
							mSyncStatusView.setVisibility(show ? View.VISIBLE
									: View.GONE);
						}
					});

			mSyncButtonView.setVisibility(View.VISIBLE);
			mSyncButtonView.animate().setDuration(shortAnimTime)
					.alpha(show ? 0 : 1)
					.setListener(new AnimatorListenerAdapter() {
						@Override
						public void onAnimationEnd(Animator animation) {
							mSyncButtonView.setVisibility(show ? View.GONE
									: View.VISIBLE);
						}
					});
		} else {
			// The ViewPropertyAnimator APIs are not available, so simply show
			// and hide the relevant UI components.
			mSyncStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
			mSyncButtonView.setVisibility(show ? View.GONE : View.VISIBLE);
		}
	}

	/**
	 * Represents an asynchronous task to call the webservice
	 */
	public class WebserviceTask extends AsyncTask<String, Integer, Boolean> {

		public static final int POST_TASK = 1;
		public static final int GET_TASK = 2;

		private static final String TAG = "WebserviceTask";

		ObjectMapper objectMapper = new ObjectMapper();

		@Override
		protected Boolean doInBackground(String... urls) {
			// TODO: attempt connect to a network service.

			try {

				String postUrl = urls[0] + urls[1];
				String pictureUrl = urls[0] + "/picture" + urls[1];
				Log.i(TAG, "Attempt connection to Webservice: " + postUrl);

				// Create a new RestTemplate instance
				RestTemplate restTemplate = new RestTemplate();

				// upload screenings
				// set the mapper for parsing the json data
				objectMapper.configure(
						DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY,
						true);
				MappingJackson2HttpMessageConverter mapper = new MappingJackson2HttpMessageConverter();
				mapper.setObjectMapper(objectMapper);

				// Add the message converter
				restTemplate.getMessageConverters().add(mapper);
				

				// get all the screeningsfor uploading
				DBAdapter db = new DBAdapterUpload(SyncActivity.this);
				db.open();
				Map<Integer, ScreeningBundle> screeningBundleMap = ((DBAdapterUpload) db)
						.getScreeningBundle();
				String getUrl = postUrl + "/"
						+ ((DBAdapterUpload) db).getAmountCities();
				db.close();

				if (screeningBundleMap != null) {
					int countScreening = 1;
					int amountScreening = screeningBundleMap.size();
					for (Map.Entry<Integer, ScreeningBundle> bundle : screeningBundleMap
							.entrySet()) {

						publishProgress(0, countScreening, amountScreening);
						// Make the HTTP POST request, marshaling the request to
						// JSON, and the response to a ResponseBundle
						PatientBundle response = restTemplate
								.postForObject(postUrl, bundle.getValue(),
										PatientBundle.class);
						Log.i(TAG, "Screening uploaded");

						if (response.getPatient().getId() != null) {
							// get all the pictures from the screening and
							// upload them
							db.open();
							((DBAdapterUpload) db).processRespond(response);
							for (itemIdPair pair : response.getItemIdList()) {
								List<byte[]> pictures = ((DBAdapterUpload) db)
										.getPictures(pair.getTabletId());
								for (byte[] pic : pictures) {

									PictureContainer picC = new PictureContainer();
									picC.setPicture(pic);
									restTemplate
											.put(pictureUrl + "/"
													+ pair.getCentralId(), picC);
									Log.w(TAG,
											"picture uploaded for "
													+ pair.getCentralId());
								}
							}
							db.close();

							db = new DBAdapterScreening(SyncActivity.this);
							db.open();
							((DBAdapterScreening) db).deleteScreening(bundle
									.getKey());
							db.close();

						} else {
							return false;
						}
					}
				}

				publishProgress(1);
				// Make the HTTP GET request
				DownloadBundle result = restTemplate.getForObject(getUrl,
						DownloadBundle.class);

				if (result.getUser() != null) {
					Log.i(TAG, "connection succeeded");

					db = new DBAdapterUser(SyncActivity.this);
					db.open();
					((DBAdapterUser) db).insertOrUpdateUser(result.getUser());
					db.close();
					db = null;

					db = new DBAdapterDownloadBundle(SyncActivity.this);
					db.open();
					// ((DBAdapterDownloadBundle)
					// db).processDownloadBundle(result);
					publishProgress(2, 0);
					((DBAdapterDownloadBundle) db).insertUserData(result
							.getUserFunction());
					((DBAdapterDownloadBundle) db).insertCityData(result
							.getCity());
					publishProgress(2, 1);
					((DBAdapterDownloadBundle) db).insertRoomData(
							result.getRoomType(), result.getRoomItem(),
							result.getItemProblem());
					publishProgress(2, 2);
					((DBAdapterDownloadBundle) db).insertPatientData(
							result.getBuildingSpec(), result.getBuildingType(),
							result.getMaritalStatus(),
							result.getMovementRestriction(),
							result.getUsedAid(), result.getPatientSpec(),
							result.getPatientBundle());
					db.close();
					// insert screenings
					for(ScreeningBundle screening: result.getScreeningBundle()) {
						db = new DBAdapterScreening(SyncActivity.this);
						db.open();
						int screeningId = (int) ((DBAdapterScreening)db).insertScreeningId(screening.getPatientId(), screening.getBuildingId(), screening.getScreeningId());
						((DBAdapterScreening)db).updateComment(screeningId, CommentFragment.SCREENING, screening.getComment());
						for(ScreeningRoomBundle room: screening.getScreeningRoomBundle()) {
							int roomId = (int) ((DBAdapterScreening)db).insertScreeningRoom(screeningId, room.getScreeningRoom().getRoomType(), room.getScreeningRoom().getName(), room.getScreeningRoom().getReferenceNumber(), room.getScreeningRoom().getFloorNumber());
							((DBAdapterScreening)db).updateComment(roomId, CommentFragment.SCREENING_ROOM, room.getScreeningRoom().getComment());
							for (ScreeningItemBundle item: room.getScreeningItemBundle()) {
								int itemId = (int) ((DBAdapterScreening)db).insertScreeningItem(roomId, item.getScreeningItem().getRoomItem());
								((DBAdapterScreening)db).updateComment(itemId, CommentFragment.SCREENING_ITEM, item.getScreeningItem().getComment());
								for (ScreeningProblem problem: item.getScreeningProblem()) {
									((DBAdapterScreening)db).insertScreeningProblem(itemId, problem.getItemProblem(), null);
								}
							}
						}
					}
					db.close();
					db = null;
					return true;
				}

			} catch (Exception ex) {
				ex.printStackTrace();
				return false;
			}

			return true;
		}

		@Override
		protected void onProgressUpdate(Integer... progress) {
			switch (progress[0]) {
			case 0:
				mSyncStatusMessage.setText("Uploaden: screening " + progress[1]
						+ " van " + progress[2]);
				mProgressBar.setProgress((mProgressBar.getMax() / 3)
						/ progress[2] * progress[1]);
				break;
			case 1:
				mSyncStatusMessage.setText("Downloaden...");
				mProgressBar.setProgress(mProgressBar.getMax() / 3 * 1);
				break;
			case 2:
				mSyncStatusMessage.setText("Data verwerken...");
				mProgressBar.setProgress((mProgressBar.getMax() / 3 * 2)
						+ mProgressBar.getMax() / 9 * 1 * progress[1]);
				break;
			}
		}

		@Override
		protected void onPostExecute(final Boolean success) {

			Log.i(TAG, "Sync finished");

			mWebserviceTask = null;
			showProgress(false);
			if (success) {
				mSyncMessage.setText("Synchronisatie voltooid");
			} else {
				mSyncMessage
						.setText("Synchronisatie mislukt, probeer opnieuw of contacteer de systeembeheerder.");
			}
			mSyncMessage.setVisibility(View.VISIBLE);
			
			isSynchronising = false;

		}
	}

	// @Override
	// protected void onResume() {
	// // animateIn this activity
	// ActivitySwitcher.animationIn(findViewById(R.id.totaal),
	// getWindowManager());
	// super.onResume();
	// }

}
